import {
  Component,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  Input,
  TemplateRef,
  ContentChild,
  ViewChild,
  ElementRef,
  Renderer2,
  AfterViewInit,
  OnDestroy,
  SimpleChanges,
  OnChanges,
} from '@angular/core';
import { NgControl } from '@angular/forms';
import { InputDirective } from '../input/input.directive';
import { TypeUtils, LvSizeLD, InputBoolean } from '../core/api';
import { ResizeObserverService } from '../core/services/resize-observer.service';

@Component({
  selector: 'lv-input-group',
  exportAs: 'lvInputGroup',
  templateUrl: './input-group.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    '[class.lv-input-group]': 'true',
    '[class.lv-input-group-large]': "lvSize === 'large'",
    '[class.lv-input-group-default]': "lvSize === 'default'",
    '[class.lv-input-addElement]': '!(lvAddBefore === null && lvAddAfter === null)',
    '[class.lv-input-group-disabled]': 'lvDisabled',
    '[class.lv-input-group-error]': 'formCtrl?.invalid && (formCtrl?.dirty || formCtrl?.touched)',
    '(click)': 'getFocus()',
    '(mousedown)': 'mousedown($event)',
  },
})
export class InputGroupComponent implements OnChanges, AfterViewInit, OnDestroy {
  @Input() @InputBoolean() lvDisabled;
  @Input() lvSize: LvSizeLD = 'default';
  @Input() lvPrefix: string | TemplateRef<any> = null;

  @Input() lvSuffix: string | TemplateRef<any> = null;

  @ContentChild(NgControl, { static: false }) formCtrl;

  @Input() lvAddAfter: string | TemplateRef<any> = null;

  @Input() lvAddBefore: string | TemplateRef<any> = null;

  @ContentChild(InputDirective, { static: false }) input;

  @ViewChild('inputPrefix', { static: false }) inputPrefix: ElementRef<any>;

  @ViewChild('inputSuffix', { static: false }) inputSuffix: ElementRef<any>;

  @ViewChild('inputAddAfter', { static: false }) inputAddAfter: ElementRef<any>;
  @ViewChild('inputAddBefore', { static: false }) inputAddBefore: ElementRef<any>;
  public typeUtils = TypeUtils;
  private _inputPrefixObserver;
  private _inputSuffixObserver;

  constructor(
    private renderer: Renderer2,
    private resizeObserver: ResizeObserverService,
    private elementRef: ElementRef,
  ) {}

  setInputSize(): void {
    if (this.input) {
      this.input.lvSize = this.lvSize;
    }
  }

  getFocus(): void {
    if (this.shouldFocus()) {
      this.input.elementRef.nativeElement.focus();
    }
  }

  shouldFocus(): boolean | string | TemplateRef<any> {
    return !(this.lvAddBefore || this.lvAddAfter) || (this.lvAddBefore && this.lvPrefix);
  }

  // 避免已经focus状态了点击搜索图标会再次触发lvOnFocus
  mousedown(e: MouseEvent): void {
    if (this.shouldFocus() && (e.target as HTMLElement).tagName !== 'INPUT') {
      e.preventDefault();
    }
  }

  ngOnDestroy(): void {
    this._inputPrefixObserver?.unobserve();
    this._inputSuffixObserver?.unobserve();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.lvDisabled) {
      this.setDisableStatus();
    }
    if (changes.lvSize) {
      this.setInputSize();
    }
  }

  setDisableStatus(): void {
    if (this.input) {
      if (this.lvDisabled && !this.input.elementRef.nativeElement.disabled) {
        this.input.elementRef.nativeElement.disabled = this.lvDisabled;
      } else {
        this.input.elementRef.nativeElement.disabled = null;
      }
    }
  }

  ngAfterViewInit(): void {
    const nativeElement = this.input.nativeElement ? this.input.nativeElement : this.input.elementRef.nativeElement;
    if (this.inputPrefix && !this.lvAddBefore) {
      this._inputPrefixObserver = this.resizeObserver.observe(this.inputPrefix.nativeElement, (): void => {
        this.renderer.setStyle(nativeElement, 'padding-left', `${this.inputPrefix.nativeElement.clientWidth + 4}px`);
      });
    }

    if (this.inputSuffix) {
      this._inputSuffixObserver = this.resizeObserver.observe(this.inputSuffix.nativeElement, (): void => {
        this.renderer.setStyle(nativeElement, 'padding-right', `${this.inputSuffix.nativeElement.clientWidth + 8}px`);

        const helpTooltip = this.elementRef.nativeElement.querySelector('lv-help-tooltip');
        if (!helpTooltip) {
          return;
        }
        this.renderer.setStyle(helpTooltip, 'right', `${this.inputSuffix.nativeElement.clientWidth + 8 * 2}px`);
      });
    }

    this.setDisableStatus();
    this.setInputSize();
  }
}
